<template>
    <a-form
        :model="formModel"
        layout="inline"
        @finish="handleSubmit"
        :rules="computedRules"
        class="gap-4"
        ref="formRef"
        v-bind="$attrs"
    >
        <a-form-item v-for="item in formItems" :key="item.name" v-bind="item">
            <!-- Input -->
            <a-input v-if="item.type === 'input'" v-model:value="formModel[item.name]" v-bind="item.componentProps" />
            <!-- InputNumber -->
            <a-input-number
                v-else-if="item.type === 'input-number'"
                v-model:value="formModel[item.name]"
                v-bind="item.componentProps"
                style="width: 100%"
            />
            <!-- Password -->
            <a-input-password
                v-else-if="item.type === 'input-password'"
                v-model:value="formModel[item.name]"
                v-bind="item.componentProps"
            />
            <!-- TextArea -->
            <a-textarea
                v-else-if="item.type === 'textarea'"
                v-model:value="formModel[item.name]"
                v-bind="item.componentProps"
            />
            <!-- Select -->
            <a-select
                v-else-if="item.type === 'select'"
                v-model:value="formModel[item.name]"
                v-bind="omit(item.componentProps!, ['options'])"
                show-search
                :options="item.componentProps?.options"
                style="min-width: 120px"
            />
            <!-- DatePicker -->
            <a-date-picker
                v-else-if="item.type === 'date-picker'"
                v-model:value="formModel[item.name]"
                v-bind="item.componentProps"
                style="width: 100%"
            />
            <!-- RangePicker -->
            <a-range-picker
                v-else-if="item.type === 'date-range-picker'"
                v-model:value="formModel[item.name]"
                v-bind="item.componentProps"
                style="width: 100%"
            />
            <!-- CheckboxGroup -->
            <a-checkbox-group
                v-else-if="item.type === 'checkbox'"
                v-model:value="formModel[item.name]"
                :options="item.componentProps.options"
            />
            <!-- RadioGroup -->
            <a-radio-group
                v-else-if="item.type === 'radio'"
                v-model:value="formModel[item.name]"
                :options="item.componentProps.options"
            />
        </a-form-item>

        <!-- 操作按钮 -->
        <a-form-item>
            <a-space>
                <a-button type="primary" html-type="submit">查询</a-button>
                <a-button @click="handleReset">重置</a-button>
            </a-space>
        </a-form-item>
    </a-form>
</template>

/** * 查询表单组件 */
<script setup lang="ts" generic="T extends Record<string, any>">
import type { RuleObject } from "ant-design-vue/es/form/interface";
import { computed, reactive } from "vue";

import type { FormItemConfig } from "../types/form-config";

const props = withDefaults(
    defineProps<{
        formItems: FormItemConfig[];
        initialValues: T; // 表单数据模型对象（同时设置了初始值）。属性必须和 formItems 中定义的 name 一致
    }>(),
    {
        formItems: () => [
            {
                name: "username",
                label: "用户名",
                type: "input",
                rules: [{ required: true, message: "请输入用户名" }],
                componentProps: { placeholder: "请输入用户名" }
            },
            {
                name: "age",
                label: "年龄",
                type: "input-number",
                rules: [{ required: true, message: "请输入年龄" }],
                componentProps: { placeholder: "请输入年龄" }
            },
            {
                type: "select",
                name: "gender",
                label: "性别",
                componentProps: {
                    placeholder: "请选择性别",
                    options: [
                        {
                            label: "男",
                            value: "male"
                        },
                        {
                            label: "女",
                            value: "female"
                        },
                        {
                            label: "未知",
                            value: "unknown"
                        }
                    ]
                }
            },
            {
                type: "date-range-picker",
                name: "dateRange",
                label: "日期范围"
            }
        ],
        initialValues: () =>
            ({
                username: "",
                gender: void 0, // 下拉框属性的初始值应为 undefined，否则无法显示 placeholder 值
                age: void 0, // 数字输入框的初始值也可设为 undefined，避免 0 的默认值
                dateRange: null as [Dayjs, Dayjs] | null // 日期范围选择框的初始值也为 null，避免默认的今天，有效值为 Dayjs 实例数组
            }) as any
    }
);

const emit = defineEmits<{
    (e: "submit", values: T): void;
    (e: "reset"): void;
}>();

// 表单实例
const formRef = ref();

// 表单模型（响应式）
const formModel = reactive({ ...props.initialValues });

// 自动收集 rules
const computedRules = computed<Record<string, RuleObject[]>>(() => {
    const rules: Record<string, RuleObject[]> = {};
    props.formItems.forEach(item => {
        if (item.rules?.length) {
            rules[item.name] = item.rules;
        }
    });
    return rules;
});

const validate = () => formRef.value?.validate();
// 提交
const handleSubmit = (values: T) => {
    validate().then(() => {
        emit("submit", values);
    });
};

// 重置
const handleReset = () => {
    Object.assign(formModel, { ...props.initialValues });
    emit("reset");
};

// 如果不使用 lodash，可以内联 omit
function omit(obj: Record<string, any>, keys: string[]) {
    if (!obj) return {};
    const res = { ...obj };
    keys.forEach(k => delete res[k]);
    return res;
}

// 暴露方法给父组件（如需要）
defineExpose({
    formRef,
    validate,
    handleSubmit,
    handleReset,
    formModel
});
</script>
